/*
	rreflect

通用反射工具包
自动穿透多层指针，获取值的底层非指针类型（reflect.Kind）与对应反射操作句柄（reflect.Value）
解决手动解引用的繁琐问题
通用化 nil 检测，支持所有可能为 nil 的类型（指针、切片、映射等），规避非 nil 类型调用反射 IsNil () 导致的 panic
简化通用类型处理场景（如动态类型转换、参数合法性校验、反射修改值）中的反射逻辑，降低反射使用门槛并减少重复编码
*/
package rreflect

import "reflect"

// Value 接收任意类型的输入值，返回其底层类型（reflect.Kind）和对应的反射值（reflect.Value）。
// 核心功能是“自动解引用所有指针层”，最终返回非指针类型的Kind和反射值，方便后续对实际值的操作。
// 参数：
//
//	i: 任意类型的输入值（可以是基础类型、指针、多层指针等，如 int、*string、**[]int 等）
//
// 返回值：
//
//	reflect.Kind: 输入值解引用后的底层类型大类（如 reflect.Int、reflect.Struct、reflect.Slice 等）
//	reflect.Value: 输入值解引用后的反射值（包含实际数据的操作句柄）
func Value(i any) (reflect.Kind, reflect.Value) {
	// 1. 获取输入值的反射值（reflect.Value）：
	// reflect.ValueOf(i) 将任意类型的 i 转换为反射包的 Value 类型，相当于获取了 i 的“万能操作句柄”，
	// 可以通过该句柄获取 i 的类型、值，甚至修改 i（如果可设置）。
	var (
		rv = reflect.ValueOf(i)
		// 2. 获取反射值的类型大类（Kind）：
		// rv.Kind() 返回该反射值对应的基础类型分类（如指针类型返回 reflect.Ptr，整数返回 reflect.Int），
		// 注意 Kind 是“类型大类”，而非具体类型（如 *int 的 Kind 是 Ptr，而非 *int）。
		rk = rv.Kind()
	)

	// 3. 循环解引用指针：若当前类型是指针（reflect.Ptr），则一直解引用到非指针类型
	// 原因：输入可能是多层指针（如 **int、*[]string），我们需要的是指针最终指向的“实际值”的类型和反射值。
	// 例：输入是 **int（指向 *int，再指向 int(10)），循环会先解引用为 *int（rk仍为Ptr），再解引用为 int（rk为Int），退出循环。
	for rk == reflect.Ptr {
		// rv.Elem()：对指针类型的反射值进行解引用，获取指针指向的实际值的反射值（如 *int 的 Elem() 是 int 的反射值）
		rv = rv.Elem()
		// 更新类型大类为解引用后的值的 Kind（如解引用 *int 后，rk 变为 reflect.Int）
		rk = rv.Kind()
	}

	// 4. 返回解引用后的底层类型和反射值
	return rk, rv
}

// IsNil 检测任意输入值是否为nil，支持所有可能为nil的类型（如指针、切片、映射、通道等），
// 对于不可能为nil的类型（如int、string、结构体等），直接返回false。
// 注意：nil的判定遵循Go的语义（如未初始化的切片为nil，空切片（len=0）不为nil）。
// 参数：
//
//	v: 任意类型的输入值（如 nil、*int(nil)、[]int(nil)、10、"abc" 等）
//
// 返回值：
//
//	bool: 若v是nil，返回true；否则返回false
func IsNil(v any) bool {
	// 1. 快速判断：若输入直接是nil（空接口的nil状态），直接返回true
	// 注：当v是未初始化的接口类型（如 var i interface{}），v == nil 为true；
	// 若接口绑定了具体类型的nil指针（如 var i interface{} = (*int)(nil)），v != nil（接口存储了类型信息），需后续反射判断。
	if v == nil {
		return true
	}

	// 2. 对非nil输入，通过反射获取其反射值和类型大类
	rv := reflect.ValueOf(v) // 获取v的反射值（操作句柄）
	rk := rv.Kind()          // 获取v的类型大类

	// 3. 判断类型是否属于“可能为nil的类型”：
	// Go中只有特定类型可能为nil（指针、切片、映射、通道、函数、接口、 unsafe.Pointer），
	// 其他类型（如int、string、结构体、数组等）不可能为nil，直接返回false。
	switch rk {
	// 以下类型支持nil值，调用rv.IsNil()判断是否为nil：
	case reflect.Chan, // 通道类型（如 chan int）
		reflect.Func,          // 函数类型（如 func()）
		reflect.Map,           // 映射类型（如 map[string]int）
		reflect.Pointer,       // 指针类型（如 *int）
		reflect.UnsafePointer, // 不安全指针类型（unsafe.Pointer）
		reflect.Interface,     // 接口类型（如 interface{}）
		reflect.Slice:         // 切片类型（如 []int）
		return rv.IsNil() // 调用反射值的IsNil()方法，返回是否为nil（如未初始化的切片返回true，已初始化的返回false）
	default:
		// 其他类型（如int、string、bool、struct、array等）不可能为nil，返回false
		return false
	}
}
